#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
package ${package}.common.bean.vo;


import ${package}.common.validator.NotIncloud;
import ${package}.common.validator.ShutterIsland;
import com.google.common.collect.Lists;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.springframework.util.Assert;

import javax.validation.constraints.NotEmpty;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Description: 搜索规则实体类
 *
 * @author wupanhua
 * @date 2019/8/6 15:28
 *
 * <pre>
 *              ${copyright}
 *      Copyright (c) 2019. All Rights Reserved.
 * </pre>
 */
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Constraint {

    private static final String EQ = "eq";
    private static final String LT = "lt";
    private static final String RT = "rt";
    private static final String LE = "le";
    private static final String RE = "re";
    private static final String LIKE = "like";
    private static final String IN = "in";
	private static final String NI = "ni";
    private static final String NE = "ne";
    private static final String NN = "nn";
    private static final String EN = "en";
	private static final String BETWEEN = "between";

    public boolean straight() {
        return StringUtils.isNotEmpty(sql);
    }

    @Getter
	private String sql = StringUtils.EMPTY;

    /**
     * 字段名称
     */
    @Length(min = 0, max = 32)
    @NotIncloud(law = {"_", "-", "*", "/", "&"})
    @ApiModelProperty("字段名称")
    private String prop;
    /**
     * 逻辑运算符
     */
    @NotEmpty
    @ShutterIsland(teddy = {"eq", "lt", "rt", "le", "re", "like", "between", "in", "ni", "ne", "nn"})
    @ApiModelProperty("逻辑运算符")
    private String op;
    /**
     * 值
     */
    @ApiModelProperty("值")
    private List<Object> value;
    /**
     * 一个值
     */
    @ApiModelProperty("一个值")
    private boolean singleValue;
    /**
     * 两个值
     */
    @ApiModelProperty("两个值")
    private boolean betweenValue;
    /**
     * 多个值
     */
    @ApiModelProperty("多个值")
    private boolean listValue;
    /**
     * 字段类型
     */
    @ApiModelProperty("字段类型")
    @ShutterIsland(teddy = {"String", "Integer", "Boolean", "Float", "Double", "Date"})
    private String fieldType;

    /**
     * Description:
     * <无法补充>
     * @author wupanhua
     * @date 11:34 2019/8/8
     * @return java.lang.String
     **/
    public String getProp() {

        char start = 'A';
        char end = 'Z';
        int startChar = (int)start;
        int endChar = (int)end;
        char[] propChars = prop.toCharArray();
        StringBuilder buffer = new StringBuilder();

        for (char propChar : propChars) {
            int aimChar = (int) propChar;
            if (aimChar >= startChar && aimChar <= endChar) {
                // 大写转小写并插入下划线
                buffer.append('_').append((char) (propChar + 32));
            } else {
                buffer.append(propChar);
            }
        }

        return buffer.toString();
    }

    public void setProp(String prop) {

        this.prop = prop;
    }

    public String getOp() {

        this.op = this.op.toLowerCase();

        switch (op) {
            case EQ:
                return "=";
            case LT:
                return "<";
            case RT:
                return ">";
            case LE:
                return "<=";
            case RE:
                return ">=";
            case NE:
                return "!=";
            case LIKE:
                StringBuilder buffer = new StringBuilder();
                for (int i = 0; i < value.size(); i++) {
                    this.value.set(i, buffer.append("%").append(value.get(0)).append("%").toString());
                }
                return op;
            case NI:
                return "not in";
            case NN:
            case EN:
	        case IN:
	        case BETWEEN:
            default:
                // 故意让系统抛出异常
	            return op;
        }
    }

    public void setOp(String op) {

	    Assert.notNull(op, "请设置正确的操作类型");
	    this.op = op.toLowerCase();
	    this.singleValue = Boolean.FALSE;
	    this.betweenValue = Boolean.FALSE;
	    this.listValue = Boolean.FALSE;
	    switch (this.op) {
		    case EQ:
		    case LT:
		    case RT:
		    case LE:
		    case RE:
		    case NE:
		    case LIKE:
			    this.singleValue = Boolean.TRUE;
			    break;
		    case IN:
		    case NI:
			    this.listValue = Boolean.TRUE;
                break;
		    case BETWEEN:
			    this.betweenValue = Boolean.TRUE;
			    break;
		    case NN:
		    case EN:
		    default:
			    break;
	    }
    }
    public List<Object> getValue() {
        if(this.op.equals(NN)) {
            return Lists.newArrayList("is not null");
        }
        if(this.op.equals(EN)) {
            return Lists.newArrayList("is null");
        }
        this.value.removeIf(item-> null==item || StringUtils.isEmpty(item.toString()));
        return this.value;
    }

    public void setValue(List<Object> value) {
        this.value = value;
    }

    public boolean isSingleValue() {
        return singleValue;
    }

    public void setSingleValue(boolean singleValue) {
        this.singleValue = singleValue;
        if (IN.equals(this.op)) {
            this.singleValue = false;
        }
    }

    public boolean isBetweenValue() {
        return betweenValue;
    }

    public void setBetweenValue(boolean betweenValue) {
        this.betweenValue = betweenValue;
        if (IN.equals(this.op)) {
            this.betweenValue = false;
        }
    }

    public boolean isListValue() {
        return listValue;
    }

    public void setListValue(boolean listValue) {
        this.listValue = listValue;
        if (IN.equals(this.op)) {
            this.listValue = true;
        }
    }

    public String getFieldType() {
        return fieldType;
    }

    public void setFieldType(String fieldType) {
        this.fieldType = fieldType;
    }

    /**
     * Description:
     * <创建一个实体类>
     * @author wupanhua
     * @date 11:35 2019/8/8
     * @return Constraint
     **/
    public static Constraint build() {
        return new Constraint();
    }

    /**
     * Description:
     * <设置筛选字段>
     * @author wupanhua
     * @date 11:36 2019/8/8
     * @param field 1
     * @return Constraint
     **/
    public Constraint putField(String field) {
        this.prop = field;
        return this;
    }

    /**
     * Description:
     * <设置操作符>
     * @author wupanhua
     * @date 11:37 2019/8/8
     * @param op 1
     * @return Constraint
     **/
    public Constraint putOp(String op) {
        this.setOp(op);
        return this;
    }

    /**
     * Description:
     * <设置值>
     * @author wupanhua
     * @date 11:37 2019/8/8
     * @param listValue 1
     * @param arrayList 2
     * @return Constraint
     **/
    public Constraint putListValus(boolean listValue, List<Object> arrayList) {

        this.setValue(arrayList);
        this.setListValue(Boolean.TRUE);

        return this;
    }

    /**
     * Description:
     * <设置值>
     * @author wupanhua
     * @date 11:37 2019/8/8
     * @param listValue 1
     * @param obj 2
     * @return Constraint
     **/
    public Constraint putValus(boolean listValue, Object ...obj) {

        List<Object> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, obj);
        this.setValue(arrayList);

        if (arrayList.isEmpty()) {
            log.error("参数值不能为空");
        } else if (arrayList.size() == 1) {
            this.setSingleValue(Boolean.TRUE);
        } else if (arrayList.size() == 2) {
            if (listValue) {
                this.setListValue(Boolean.FALSE);
            } else {
                this.setBetweenValue(Boolean.TRUE);
            }
        } else if (arrayList.size() > 2) {
            this.setListValue(Boolean.TRUE);
        }

        return this;
    }

    /**
     * Description:
     * <设置值类型>
     * @author wupanhua
     * @date 11:38 2019/8/8
     * @param type 1
     * @return Constraint
     **/
    public Constraint putValueType(String type) {
        this.setFieldType(type);
        return this;
    }

    /**
     * Description:
     * <逻辑运算符>
     * @author wupanhua
     * @date 11:38 2019/8/8
     **/
    public enum LOPERATE {
        /**
         * 等于 小于 大于 小于等于 大于等于 模糊查询 之间 在..内
         */
        EQ("eq", "等于"),
        LT("lt", "小于"),
        RT("rt", "大于"),
        LE("le", "小于等于"),
        RE("re", "大于等于"),
        LIKE("like", "模糊查询"),
        BETWEEN("between", "之间"),
	    IN("in", "在..内"),
	    NI("not in", "不在..内"),
        NE("ne", "不等于"),
        NN("nn", "不为null"),
        EN("en", "null")
        ;

        private String operation;
        private String descript;

        LOPERATE(String operation, String descript) {
            this.operation = operation;
            this.descript = descript;
        }

        public String getOperation() {
            return operation;
        }

        public String getDescript() {
            return descript;
        }
    }

    public enum DATATYPE {

        /**
         * 字符串 整型 布尔型 单精度浮点型 双精度浮点型 日期型
         */
        STRING("String", "字符串"),
        INTEGER("Integer", "整型"),
        BOOLEAN("Boolean", "布尔型"),
        FLOAT("Float", "单精度浮点型"),
        DOUBLE("Double", "双精度浮点型"),
        DATE("Date", "日期型");

        private String type;
        private String descript;

        DATATYPE(String type, String descript) {
            this.type = type;
            this.descript = descript;
        }

        public String getType() {
            return type;
        }

        public String getDescript() {
            return descript;
        }
    }
}
